package com.fruit.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

import javax.annotation.Resource;

import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.transform.Transformers;

import com.fruit.dao.BaseDao;
import com.fruit.system.model.Pager;

public class BaseDaoImpl<T> implements BaseDao<T>
{
	private SessionFactory sessionFactory;
	private Class<T> clz;

	@SuppressWarnings("unchecked")
	protected BaseDaoImpl()
	{
		ParameterizedType type=(ParameterizedType) this.getClass().getGenericSuperclass();
		clz=(Class<T>) type.getActualTypeArguments()[0];
	}
	
	@Resource
	protected void setSessionFactory(SessionFactory sessionFactory)
	{
		this.sessionFactory=sessionFactory;
	}
	
	protected Session getSession()
	{
		return sessionFactory.getCurrentSession();
	}
	

	@Override
	public Serializable saveEntity(T t)
	{
		return getSession().save(t);
	}
	
	
	@Override
	public void saveOrUpdateEntity(T t)
	{
		getSession().saveOrUpdate(t);
	}
	
	
	@Override
	public void updateEntity(T t)
	{
		getSession().update(t);
	}
	
	
	@Override
	public void deleteEntity(T t)
	{
		getSession().delete(t);
	}
	

	@Override
	@SuppressWarnings("unchecked")
	public T loadEntity(Serializable id)
	{
		return (T) getSession().load(clz, id);
	}
	
	
	@Override
	@SuppressWarnings("unchecked")
	public T getEntity(Serializable id)
	{
		return (T) getSession().get(clz, id);
	}
	
	
	@Override
	public List<T> findAllEntity()
	{
		
		return findEntityByHql("from "+clz.getName());
	}
	
	
	@Override
	@SuppressWarnings("unchecked")
	public List<T> findEntityByHql(String hql, Object...values)
	{
		return initQuery(hql, values).list();
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public Pager<T> findAllEntityByPager()
	{
		return (Pager<T>) findEntityByPager("from "+clz.getName());
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public Pager<Object> findEntityByPager(String hql,Object...values)
	{
		Query query=initQuery(hql, values);
		Pager<Object> pager=new Pager<Object>();
		query.setFirstResult(pager.getPageOffset());
		query.setMaxResults(pager.getPageSize());
		pager.setDatas(query.list());
		pager.setTotalRecords(getCountByHql(hql, values));
		return pager;
	}
	
	@Override
	public Object findUniqueResultByHql(String hql, Object...values)
	{
		return initQuery(hql, values).uniqueResult();
	}
	
	
	@Override
	public void batchEntityByHql(String hql, Object...values)
	{
		initQuery(hql, values).executeUpdate();
	}
	
	
	@Override
	@SuppressWarnings("unchecked")
	public List<T> executeFindSql(String sql, Object...values)
	{
		return initSqlQuery(sql, values).addEntity(clz).list();
	}
	
	
	@Override
	@SuppressWarnings("unchecked")
	public <E> List<E> executeFindSql(Class<E> clz, String sql, Object...values)
	{
		SQLQuery sqlQuery=initSqlQuery(sql, values);
		sqlQuery.setResultTransformer(Transformers.aliasToBean(clz));
		return sqlQuery.list();
	}
	
	@Override
	public Object findUniqueResultBySql(String hql, Object...values)
	{
		return initSqlQuery(hql, values).uniqueResult();
	}
	
	@Override
	public void executeUpdateSql(String sql, Object...values)
	{
		initSqlQuery(sql, values).executeUpdate();
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public Pager<T> executeFindSqlByPager(String sql, Object...values)
	{
		SQLQuery sqlQuery=initSqlQuery(sql, values);
		Pager<Object> pager=new Pager<Object>();
		sqlQuery.setFirstResult(pager.getPageOffset());
		sqlQuery.setMaxResults(pager.getPageSize());
		pager.setDatas(sqlQuery.list());
		pager.setTotalRecords(getCountBySql(sql, values));
		return (Pager<T>) pager;
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public <E> Pager<E> executeFindSqlByPager(Class<E> clz, String sql, Object...values)
	{
		SQLQuery sqlQuery=initSqlQuery(sql, values);
		sqlQuery.setResultTransformer(Transformers.aliasToBean(clz));
		Pager<Object> pager=new Pager<Object>();
		sqlQuery.setFirstResult(pager.getPageOffset());
		sqlQuery.setMaxResults(pager.getPageSize());
		pager.setDatas(sqlQuery.list());
		pager.setTotalRecords(getCountBySql(sql, values));
		return (Pager<E>) pager;
	}
	
	private Query initQuery(String hql, Object...values)
	{
		Query query=getSession().createQuery(hql);
		initParams(query, values);
		return query;
	}
	
	private SQLQuery initSqlQuery(String sql, Object...values)
	{
		SQLQuery sqlQuery=getSession().createSQLQuery(sql);
		initParams(sqlQuery, values);
		return sqlQuery;
	}
	
	private void initParams(Query query, Object ...values)
	{
		if(values!=null&&values.length>0)
		{
			for(int i=0; i<values.length; i++)
			{
				query.setParameter(i, values[i]);
			}
		}
	}
	
	
	@Override
	public long getCountByHql(String hql, Object...values)
	{
		String fromHql=hql.substring(hql.indexOf("from"));
		String countHql="select count(*) "+fromHql;
		countHql.replaceAll("fetch", "");
		long total=(Long) this.findUniqueResultByHql(countHql,values);
		return total;
	}
	
	@Override
	public long getCountBySql(String sql, Object...values)
	{
		String fromSql=sql.substring(sql.indexOf("from"));
		String countSql="select count(*) "+fromSql;
		countSql.replaceAll("fetch", "");
		long total=(Long) this.findUniqueResultBySql(countSql,values);
		return total;
	}
}


